package copyengine.resource
{
	import copyengine.CopyEngine;
	import copyengine.resource.dto.CEResInitDTOSubSwfSymbolPackge;
	import copyengine.resource.dto.ResInitDTO;
	import copyengine.resource.file.CEDataResourceFile;
	import copyengine.resource.file.CEFontResourceFile;
	import copyengine.resource.file.CEPicResourceFile;
	import copyengine.resource.file.CESwfResourceFile;
	import copyengine.resource.file.CEXmlResourceFile;
	import copyengine.resource.file.ICEResFile;
	import copyengine.resource.file.sound.CESoundResourceFile;
	import copyengine.resource.loadqueue.CEResLoadQueue;
	import copyengine.utils.debug.CELog;

	import flash.display.DisplayObject;
	import flash.system.ApplicationDomain;
	import flash.utils.Dictionary;

	import org.puremvc.as3.interfaces.IFacade;

	public final class CEResManger
	{
		private static var _instance:CEResManger;

		public static function get instance():CEResManger
		{
			if (_instance == null)
			{
				_instance = new CEResManger();
			}
			return _instance;
		}

		/**
		 * hold all resFile reference, no matter the file is been load or not.
		 */
		private var allResFile:Dictionary;

		/**
		 * hold an reference of current loadQueue , in case want load an new res during queue load in progress.
		 */
		private var currentLoadQueue:CEResLoadQueue;

		/**
		 * use to notification other system.
		 */
		private var facade:IFacade;

		private var lazyLoadIconDomain:ApplicationDomain;

		public function CEResManger()
		{
		}

		/**
		 * basicConfig::
		 * 		in basic config only define the loadFileName(uniqueName) , and load path
		 * <root>
		 * 		<file name="a.swf"  path ="res\swf\a.swf">
		 * 		...
		 * </root>
		 * this file path will change by deploy tools like change path to "127.0.0.1\project\abc\res\swf\a.17243.swf"
		 *
		 * expandConfig::
		 * 		this config is replenish for the basic config , because CEResManger not only need to know the load res path but
		 * also need to the type of the file, like type="swf" type="xml" etc, for each type will use each type own loader. same as other
		 * replenish parameter
		 * <root>
		 * 		<file name="a.swf" type="swf" weight="375" loadQueue="perload"/>
		 * 		...
		 * </root>
		 *
		 */
		public function initialize(_basicConfig:XML, _expandConfig:XML, _facade:IFacade, _lazyLoadIconDomain:ApplicationDomain):void
		{
			lazyLoadIconDomain = _lazyLoadIconDomain;
			facade = _facade;
			analyseConfig(_basicConfig, _expandConfig, _lazyLoadIconDomain);
		}

		private function analyseConfig(_basicConfig:XML, _expandConfig:XML, _lazyLoadIconDomain:ApplicationDomain):void
		{
			var dtoTempVector:Vector.<ResInitDTO> = new Vector.<ResInitDTO>();
			allResFile = new Dictionary();

			//analyse expandConfig first , beacuse it contain the file type
			for each (var expandElement:XML in _expandConfig.file)
			{
				//initialze dto(not full init ,beacuse filePath need use basicConfig to init)
				var dto:ResInitDTO = new ResInitDTO();
				dto.resUniqueName = expandElement.@name;
				dto.loadQueueName = expandElement.@loadQueue;
				dto.maxFileWeight = expandElement.@weight;
				dto.allSubSwfSymbolPackageVector = new Vector.<CEResInitDTOSubSwfSymbolPackge>();
				for each (var symbolElement:XML in expandElement.symbol)
				{
					var subSymbolPackage:CEResInitDTOSubSwfSymbolPackge = new CEResInitDTOSubSwfSymbolPackge();
					subSymbolPackage.swfSymbolName = symbolElement.@name;
					subSymbolPackage.swfFileWidth = symbolElement.@width;
					subSymbolPackage.swfFileHeight = symbolElement.@height;
					subSymbolPackage.swfFilePosX = symbolElement.@x;
					subSymbolPackage.swfFilePosY = symbolElement.@y;

					dto.allSubSwfSymbolPackageVector.push(subSymbolPackage);
				}
				dtoTempVector.push(dto);

				//link the resFile to dictionary
				allResFile[dto.resUniqueName] = getResFileByType(expandElement.@fileType);
			}

			//analyse basicConfig
			for each (var basicElement:XML in _basicConfig.files)
			{
				var fileName:String = basicElement.@file;
				var filePath:String = CopyEngine.CONST_FOLDER_PREFIX + basicElement.@path;
				for (var i:int = 0; i < dtoTempVector.length; i++)
				{
					if (dtoTempVector[i].resUniqueName == fileName)
					{
						var resFile:ICEResFile = allResFile[fileName];
						// some type like init will not record in allRedFile Dictionary 
						if (resFile != null)
						{
							dtoTempVector[i].filePath = filePath;
							resFile.initialize(dtoTempVector[i]);
							dtoTempVector.splice(i, 1);
						}
						break;
					}
				}
			}
			dtoTempVector.length = 0;
			dtoTempVector = null;
		}

		/**
		 * get the resFile , no matter loaded or not.
		 *
		 * WARNINIG::
		 *
		 * 		this function will call by other Utils function , like UIUtils.getSprite(_symbolName,_fileName).
		 */
		public function getResFile(_name:String):ICEResFile
		{
			return allResFile[_name];
		}

		/**
		 * 判断某个文件swf是否存在
		 */
		public function isFileExist(_name:String):Boolean
		{
			return allResFile[_name] != null;
		}

		/**
		 * 添加一个ResFile到缓存中,大部分情况下ResFile都会从initialize函数中被添加进来，
		 * 但是当游戏中途请求的URL资源，例如某人头像等等，这些资源会在游戏运行后被添加
		 */
		public function addResFile(_resFile:ICEResFile, _key:String):void
		{
			allResFile[_key] = _resFile;
		}

		/**
		 * load 所有匹配正则字符串的文件，用来load某个语言区域下的所有文件
		 */
		public function loadResFileByRegExp(_regExp:String):void
		{
			var pattern:RegExp = new RegExp(_regExp);
			for (var key:String in allResFile)
			{
				if (pattern.test(key))
				{
					loadResFileByFileName(key);
				}
			}
		}

		/**
		 * load an group res by queueName.
		 * normally this will happen when user already playing the game.
		 * in initialize step
		 * 1`loadBasicRes(perLoadQueue)
		 * 2`loadUserInfoFromServer
		 * 3`loadUserFirstScreenRes(like when user in MainPlayScene , in this step will load all user alrady placeed object)
		 * 4`changeToMainPlayScene
		 * 5`start loadResByQueue
		 * 		this time will load other resFile , like the res will show in shop.(usering not use immediately);
		 */
		public function loadResByQueueName(_name:String):void
		{
			if (currentLoadQueue == null)
			{
				currentLoadQueue = new CEResLoadQueue(facade, onLoadQueueComplate);
			}
			for each (var resFile:ICEResFile in allResFile)
			{
				if (resFile.loadQueueName == _name && resFile.loadState == CEResConfig.LOAD_STATE_UNLOAD)
				{
					currentLoadQueue.addResToLoadQueue(resFile);
				}
			}
		}

		public function loadResFileByFileName(_fileName:String, _callBack:Function = null):void
		{
			var resFile:ICEResFile = allResFile[_fileName];
			if (resFile != null)
			{
				if (resFile.loadState == CEResConfig.LOAD_STATE_LOADED)
				{
					_callBack && _callBack();
				}
				else
				{
					resFile.addResLoadFinishedCallBack(_callBack);
					loadResFile(resFile);
				}
			}
			else
			{
				CELog.log("Can't Find ResFile Name :" + _fileName);
			}
		}

		public function isFileLoaded(_fileName:String):Boolean
		{
			var resFile:ICEResFile = allResFile[_fileName];
			return resFile.loadState == CEResConfig.LOAD_STATE_LOADED;
		}

		/**
		 * 清空监听加载素材成功的回调函数，当上层某个调用需要监听某个素材是否加载成功时候
		 * 会在loadResFileByFileName时候设置回调函数，不过素材加载中途由于逻辑变动导致不需要监听
		 * 当前素材加载完成则调用该函数取消callBack
		 */
		public function cleanResCallBackFunction(_fileName:String):void
		{
			var resFile:ICEResFile = allResFile[_fileName];
			if (resFile != null)
			{
				resFile.removeResLoadFinishedCallBack(null);
			}
		}

		public function getLazyLoadIcon():DisplayObject
		{
			var IconClass:Class = lazyLoadIconDomain.getDefinition("Symbol") as Class;
			return new IconClass();
		}

		private function loadResFile(_resFile:ICEResFile):void
		{
			if (currentLoadQueue == null)
			{
				currentLoadQueue = new CEResLoadQueue(facade, onLoadQueueComplate);
			}
			if (_resFile.loadState == CEResConfig.LOAD_STATE_UNLOAD)
			{
				currentLoadQueue.addResToLoadQueue(_resFile);
			}
		}


		private function onLoadQueueComplate():void
		{
			currentLoadQueue = null;
			facade.sendNotification(CEResMangerNotification.LOADQUEUE_LOAD_COMPLATE);
		}

		/**
		 *WARNINIG::
		 *
		 * 		不是所有素材Type都会在这个函数中找到，因为这个函数只用来初始化，对于游戏运行中添加的typeFile
		 * 这个函数中不会返回
		 */
		private function getResFileByType(_type:String):ICEResFile
		{
			switch (_type)
			{
				case "swf":
					return new CESwfResourceFile();
					break;
				case "bin":
					return new CEXmlResourceFile();
					break;
				case "font":
					return new CEFontResourceFile();
					break;
				case "music":
					return new CESoundResourceFile();
					break;
				case "data":
					return new CEDataResourceFile();
					break;
				case "img":
					return new CEPicResourceFile();
					break;
			}
			return null;
		}

	}
}
